Support named themed window icons.
authorMatthias Clasen <matthiasc@src.gnome.org>
Sat, 17 Jul 2004 03:55:07 +0000 (03:55 +0000)
committerMatthias Clasen <matthiasc@src.gnome.org>
Sat, 17 Jul 2004 03:55:07 +0000 (03:55 +0000)
ChangeLog
ChangeLog.pre-2-10
ChangeLog.pre-2-6
ChangeLog.pre-2-8
docs/reference/ChangeLog
docs/reference/gtk/gtk-sections.txt
gtk/gtkicontheme.c
gtk/gtkicontheme.h
gtk/gtkwindow.c
gtk/gtkwindow.h

index aece06a44ed5ab50002cac86392b129fc0363823..a65b6a3e6c218eb02245c8647dee8efcf87300be 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,21 @@
+Fri Jul 16 23:20:34 2004  Matthias Clasen  <maclas@gmx.de>
+
+       Support themed window icons.  (#92346, Calum Benson)
+       
+       * gtk/gtkicontheme.c (gtk_icon_theme_get_icon_sizes): New 
+       function to obtain information about the sizes in which an
+       icon is available.  
+
+       * gtk/gtkwindow.h: 
+       * gtk/gtkwindow.c (gtk_window_class_init): 
+       (gtk_window_set_icon_name): 
+       (gtk_window_get_icon_name): Add an "icon_name" property
+       (gtk_window_set_default_icon_name): ...and a default icon name. 
+       (icon_list_from_theme): 
+       (update_themed_icon): New auxiliary functions to create a 
+       list of all available sizes of a themed icon and update the
+       window icon list from it.
+
 2004-07-16  Matthias Clasen  <mclasen@redhat.com>
 
        * gtk/gtkcombobox.c (gtk_combo_box_scroll_event): Make 
index aece06a44ed5ab50002cac86392b129fc0363823..a65b6a3e6c218eb02245c8647dee8efcf87300be 100644 (file)
@@ -1,3 +1,21 @@
+Fri Jul 16 23:20:34 2004  Matthias Clasen  <maclas@gmx.de>
+
+       Support themed window icons.  (#92346, Calum Benson)
+       
+       * gtk/gtkicontheme.c (gtk_icon_theme_get_icon_sizes): New 
+       function to obtain information about the sizes in which an
+       icon is available.  
+
+       * gtk/gtkwindow.h: 
+       * gtk/gtkwindow.c (gtk_window_class_init): 
+       (gtk_window_set_icon_name): 
+       (gtk_window_get_icon_name): Add an "icon_name" property
+       (gtk_window_set_default_icon_name): ...and a default icon name. 
+       (icon_list_from_theme): 
+       (update_themed_icon): New auxiliary functions to create a 
+       list of all available sizes of a themed icon and update the
+       window icon list from it.
+
 2004-07-16  Matthias Clasen  <mclasen@redhat.com>
 
        * gtk/gtkcombobox.c (gtk_combo_box_scroll_event): Make 
index aece06a44ed5ab50002cac86392b129fc0363823..a65b6a3e6c218eb02245c8647dee8efcf87300be 100644 (file)
@@ -1,3 +1,21 @@
+Fri Jul 16 23:20:34 2004  Matthias Clasen  <maclas@gmx.de>
+
+       Support themed window icons.  (#92346, Calum Benson)
+       
+       * gtk/gtkicontheme.c (gtk_icon_theme_get_icon_sizes): New 
+       function to obtain information about the sizes in which an
+       icon is available.  
+
+       * gtk/gtkwindow.h: 
+       * gtk/gtkwindow.c (gtk_window_class_init): 
+       (gtk_window_set_icon_name): 
+       (gtk_window_get_icon_name): Add an "icon_name" property
+       (gtk_window_set_default_icon_name): ...and a default icon name. 
+       (icon_list_from_theme): 
+       (update_themed_icon): New auxiliary functions to create a 
+       list of all available sizes of a themed icon and update the
+       window icon list from it.
+
 2004-07-16  Matthias Clasen  <mclasen@redhat.com>
 
        * gtk/gtkcombobox.c (gtk_combo_box_scroll_event): Make 
index aece06a44ed5ab50002cac86392b129fc0363823..a65b6a3e6c218eb02245c8647dee8efcf87300be 100644 (file)
@@ -1,3 +1,21 @@
+Fri Jul 16 23:20:34 2004  Matthias Clasen  <maclas@gmx.de>
+
+       Support themed window icons.  (#92346, Calum Benson)
+       
+       * gtk/gtkicontheme.c (gtk_icon_theme_get_icon_sizes): New 
+       function to obtain information about the sizes in which an
+       icon is available.  
+
+       * gtk/gtkwindow.h: 
+       * gtk/gtkwindow.c (gtk_window_class_init): 
+       (gtk_window_set_icon_name): 
+       (gtk_window_get_icon_name): Add an "icon_name" property
+       (gtk_window_set_default_icon_name): ...and a default icon name. 
+       (icon_list_from_theme): 
+       (update_themed_icon): New auxiliary functions to create a 
+       list of all available sizes of a themed icon and update the
+       window icon list from it.
+
 2004-07-16  Matthias Clasen  <mclasen@redhat.com>
 
        * gtk/gtkcombobox.c (gtk_combo_box_scroll_event): Make 
index 96ebbc3b0d424562a4e135d0e85867aa6a9be94d..43a6ae19107e849b50a00f782d5a6dcfff32c76a 100644 (file)
@@ -1,3 +1,8 @@
+Fri Jul 16 23:54:18 2004  Matthias Clasen  <maclas@gmx.de>
+
+       * gtk/gtk-sections.txt: Add new GtkWindow and GtkIconTheme 
+       functions for named themed window icons.
+
 2004-07-16  Matthias Clasen  <mclasen@redhat.com>
 
        * gtk/gtk-sections.txt: 
index 84d293000f958f054a206b8b144316f448a029ee..c9ea44a285c0b2edafd25a423e4f46e88b8b1f23 100644 (file)
@@ -4559,6 +4559,7 @@ gtk_window_get_frame_dimensions
 gtk_window_get_has_frame
 gtk_window_get_icon
 gtk_window_get_icon_list
+gtk_window_get_icon_name
 gtk_window_get_mnemonic_modifier
 gtk_window_get_modal
 gtk_window_get_position
@@ -4578,9 +4579,11 @@ gtk_window_resize
 gtk_window_set_default_icon_list
 gtk_window_set_default_icon
 gtk_window_set_default_icon_from_file
+gtk_window_set_default_icon_name
 gtk_window_set_icon
 gtk_window_set_icon_list
 gtk_window_set_icon_from_file
+gtk_window_set_icon_name
 gtk_window_set_auto_startup_notification
 <SUBSECTION Standard>
 GTK_WINDOW
@@ -5308,6 +5311,7 @@ gtk_icon_theme_has_icon
 gtk_icon_theme_lookup_icon
 gtk_icon_theme_load_icon
 gtk_icon_theme_list_icons
+gtk_icon_theme_get_icon_sizes
 gtk_icon_theme_get_example_icon_name
 gtk_icon_theme_rescan_if_needed
 gtk_icon_theme_add_builtin_icon
index c4b30f3672c03e1a38a79f0ad420dfb1dc7cd8a3..ef04e1c11154be903545f5caf563b8785aa09eb3 100644 (file)
@@ -1295,6 +1295,77 @@ gtk_icon_theme_has_icon (GtkIconTheme *icon_theme,
   return FALSE;
 }
 
+static void
+add_size (gpointer  key,
+         gpointer  value,
+         gpointer  user_data)
+{
+  gint **res_p = user_data;
+
+  **res_p = GPOINTER_TO_INT (key);
+
+  *res_p++;
+}
+
+/**
+ * gtk_icon_theme_get_icon_sizes:
+ * @icon_theme: a #GtkIconTheme
+ * @icon_name: the name of an icon
+ * 
+ * Returns an array of integers describing the sizes at which
+ * the icon is available without scaling. A size of -1 means 
+ * that the icon is available in a scalable format. The array 
+ * is zero-terminated.
+ * 
+ * Return value: An newly allocated array describing the sizes at
+ * which the icon is available.
+ *
+ * Since: 2.6
+ **/
+gint *
+gtk_icon_theme_get_icon_sizes (GtkIconTheme *icon_theme,
+                              const char   *icon_name)
+{
+  GList *l, *d;
+  GHashTable *sizes;
+  gint *result;
+  guint suffix;
+  
+  GtkIconThemePrivate *priv;
+
+  g_return_val_if_fail (GTK_IS_ICON_THEME (icon_theme), FALSE);
+  
+  priv = icon_theme->priv;
+
+  ensure_valid_themes (icon_theme);
+
+  sizes = g_hash_table_new (g_direct_hash, g_direct_equal);
+
+  for (l = priv->themes; l; l = l->next)
+    {
+      IconTheme *theme = l->data;
+      for (d = theme->dirs; d; d = d->next)
+       {
+         IconThemeDir *dir = d->data;
+         
+         suffix = GPOINTER_TO_UINT (g_hash_table_lookup (dir->icons, icon_name));
+         if (suffix != ICON_SUFFIX_NONE)
+           {
+             if (suffix == ICON_SUFFIX_SVG)
+               g_hash_table_insert (sizes, GINT_TO_POINTER (-1), NULL);
+             else
+               g_hash_table_insert (sizes, GINT_TO_POINTER (dir->size), NULL);
+           }
+       }
+    }
+
+  result = g_new0 (gint, g_hash_table_size (sizes) + 1);
+
+  g_hash_table_foreach (sizes, add_size, &result);
+  g_hash_table_destroy (sizes);
+  
+  return result;
+}
 
 static void
 add_key_to_hash (gpointer  key,
@@ -2275,7 +2346,7 @@ icon_info_ensure_scale_and_pixbuf (GtkIconInfo *icon_info,
  * 
  * Renders an icon previously looked up in an icon theme using
  * gtk_icon_theme_lookup_icon(); the size will be based on the size
- * pssed to gtk_icon_theme_lookup_icon(). Note that the resulting
+ * passed to gtk_icon_theme_lookup_icon(). Note that the resulting
  * pixbuf may not be exactly this size; an icon theme may have icons
  * that differ slightly from their nominal sizes, and in addition GTK+
  * will avoid scaling icons that it considers sufficiently close to the
index 33bd6625fa20c696fe7437588ed007928390d743..c97d7a130542bab1f0580f9faabfc68bcbd25586 100644 (file)
@@ -116,6 +116,8 @@ void          gtk_icon_theme_set_custom_theme      (GtkIconTheme
 
 gboolean      gtk_icon_theme_has_icon              (GtkIconTheme                *icon_theme,
                                                    const gchar                 *icon_name);
+gint         *gtk_icon_theme_get_icon_sizes        (GtkIconTheme                *icon_theme,
+                                                   const gchar                 *icon_name);
 GtkIconInfo * gtk_icon_theme_lookup_icon           (GtkIconTheme                *icon_theme,
                                                    const gchar                 *icon_name,
                                                    gint                         size,
index 9ffe43b7e61943dcfdaac75c809b0ca11a4be07b..a6b9c30bf9b6b56529399b5b9c630e7039e04aaa 100644 (file)
@@ -38,6 +38,7 @@
 #include "gtkkeyhash.h"
 #include "gtkmain.h"
 #include "gtkiconfactory.h"
+#include "gtkicontheme.h"
 #include "gtkintl.h"
 #include "gtkmarshalers.h"
 #include "gtkplug.h"
@@ -70,6 +71,7 @@ enum {
   PROP_DEFAULT_HEIGHT,
   PROP_DESTROY_WITH_PARENT,
   PROP_ICON,
+  PROP_ICON_NAME,
   PROP_SCREEN,
   PROP_TYPE_HINT,
   PROP_SKIP_TASKBAR_HINT,
@@ -91,9 +93,11 @@ typedef struct
   GList     *icon_list;
   GdkPixmap *icon_pixmap;
   GdkPixmap *icon_mask;
+  gchar     *icon_name;
   guint      realized : 1;
   guint      using_default_icon : 1;
   guint      using_parent_icon : 1;
+  guint      using_themed_icon : 1;
 } GtkWindowIconInfo;
 
 typedef struct {
@@ -261,6 +265,10 @@ static void     gtk_window_set_default_size_internal (GtkWindow    *window,
                                                       gint          height,
                                                      gboolean      is_geometry);
 
+static void     update_themed_icon                    (GtkIconTheme *theme,
+                                                      GtkWindow    *window);
+static GList   *icon_list_from_theme                  (GtkWidget    *widget,
+                                                      const gchar  *name);
 static void     gtk_window_realize_icon               (GtkWindow    *window);
 static void     gtk_window_unrealize_icon             (GtkWindow    *window);
 
@@ -273,6 +281,7 @@ static GHashTable  *mnemonic_hash_table = NULL;
 static GtkBinClass *parent_class = NULL;
 static guint        window_signals[LAST_SIGNAL] = { 0 };
 static GList       *default_icon_list = NULL;
+static gchar       *default_icon_name = NULL;
 static guint        default_icon_serial = 0;
 static gboolean     disable_startup_notification = FALSE;
 static gboolean     sent_startup_notification = FALSE;
@@ -539,6 +548,22 @@ gtk_window_class_init (GtkWindowClass *klass)
                                                         GDK_TYPE_PIXBUF,
                                                         G_PARAM_READWRITE));
   
+  /**
+   * GtkWindow:icon-name:
+   *
+   * The :icon-name property specifies the name of the themed icon to
+   * use as the window icon. See #GtkIconTheme for more details.
+   *
+   * Since: 2.6
+   */
+  g_object_class_install_property (gobject_class,
+                                   PROP_ICON_NAME,
+                                   g_param_spec_string ("icon_name",
+                                                        P_("Icon Name"),
+                                                        P_("Name of the themed icon for this window"),
+                                                       NULL,
+                                                        G_PARAM_READWRITE));
+  
   g_object_class_install_property (gobject_class,
                                   PROP_SCREEN,
                                   g_param_spec_object ("screen",
@@ -858,6 +883,9 @@ gtk_window_set_property (GObject      *object,
       gtk_window_set_icon (window,
                            g_value_get_object (value));
       break;
+    case PROP_ICON_NAME:
+      gtk_window_set_icon_name (window, g_value_get_string (value));
+      break;
     case PROP_SCREEN:
       gtk_window_set_screen (window, g_value_get_object (value));
       break;
@@ -949,6 +977,9 @@ gtk_window_get_property (GObject      *object,
     case PROP_ICON:
       g_value_set_object (value, gtk_window_get_icon (window));
       break;
+    case PROP_ICON_NAME:
+      g_value_set_string (value, gtk_window_get_icon_name (window));
+      break;
     case PROP_SCREEN:
       g_value_set_object (value, window->screen);
       break;
@@ -2430,6 +2461,14 @@ get_icon_info (GtkWindow *window)
                             "gtk-window-icon-info");
 }
      
+static void
+free_icon_info (GtkWindowIconInfo *info)
+{
+  g_free (info->icon_name);
+  g_free (info);
+}
+
+
 static GtkWindowIconInfo*
 ensure_icon_info (GtkWindow *window)
 {
@@ -2443,7 +2482,7 @@ ensure_icon_info (GtkWindow *window)
       g_object_set_data_full (G_OBJECT (window),
                               "gtk-window-icon-info",
                               info,
-                              g_free);
+                              (GDestroyNotify)free_icon_info);
     }
 
   return info;
@@ -2599,13 +2638,50 @@ get_pixmap_and_mask (GdkWindow          *window,
     }
 }
 
+static GList *
+icon_list_from_theme (GtkWidget    *widget,
+                     const gchar  *name)
+{
+  GList *list;
+
+  GtkIconTheme *icon_theme;
+  GdkPixbuf *icon;
+  gint *sizes;
+  gint i;
+
+  icon_theme = gtk_icon_theme_get_for_screen (gtk_widget_get_screen (widget));
+
+  sizes = gtk_icon_theme_get_icon_sizes (icon_theme, name);
+  list = NULL;
+
+  for (i = 0; sizes[i]; i++)
+    {      
+      /* FIXME 
+       * We need an EWMH extension to handle scalable icons 
+       * by passing their name to the WM. For now just use a 
+       * fixed size of 48.
+       */ 
+      if (sizes[i] == -1)
+       icon = gtk_icon_theme_load_icon (icon_theme, name,
+                                        48, 0, NULL);
+      else
+       icon = gtk_icon_theme_load_icon (icon_theme, name,
+                                        sizes[i], 0, NULL);
+      if (icon)
+       list = g_list_append (list, icon);
+    }
+
+  return list;
+}
+
+
 static void
 gtk_window_realize_icon (GtkWindow *window)
 {
   GtkWidget *widget;
   GtkWindowIconInfo *info;
   GList *icon_list;
-  
+
   widget = GTK_WIDGET (window);
 
   g_return_if_fail (widget->window != NULL);
@@ -2626,9 +2702,17 @@ gtk_window_realize_icon (GtkWindow *window)
   
   info->using_default_icon = FALSE;
   info->using_parent_icon = FALSE;
+  info->using_themed_icon = FALSE;
   
   icon_list = info->icon_list;
-  
+
+  /* Look up themed icon */
+  if (icon_list == NULL && info->icon_name) 
+    {
+      icon_list = icon_list_from_theme (widget, info->icon_name);
+      info->using_themed_icon = TRUE;  
+    }
+
   /* Inherit from transient parent */
   if (icon_list == NULL && window->transient_parent)
     {
@@ -2644,6 +2728,14 @@ gtk_window_realize_icon (GtkWindow *window)
       if (icon_list)
         info->using_default_icon = TRUE;
     }
+
+  /* Look up themed icon */
+  if (icon_list == NULL && default_icon_name) 
+    {
+      icon_list = icon_list_from_theme (widget, default_icon_name);
+      info->using_default_icon = TRUE;
+      info->using_themed_icon = TRUE;  
+    }
   
   gdk_window_set_icon_list (widget->window, icon_list);
 
@@ -2663,6 +2755,18 @@ gtk_window_realize_icon (GtkWindow *window)
                        info->icon_mask);
 
   info->realized = TRUE;
+  
+  if (info->using_themed_icon) 
+    {
+      GtkIconTheme *icon_theme;
+
+      g_list_foreach (icon_list, (GFunc) g_object_unref, NULL);
+      g_list_free (icon_list);
+      icon_theme = gtk_icon_theme_get_for_screen (gtk_widget_get_screen (GTK_WIDGET (window)));
+      g_signal_connect (icon_theme, "changed",
+                       G_CALLBACK (update_themed_icon), window);
+    }
 }
 
 static void
@@ -2687,11 +2791,21 @@ gtk_window_unrealize_icon (GtkWindow *window)
   info->icon_pixmap = NULL;
   info->icon_mask = NULL;
 
+  if (info->using_themed_icon)
+    {
+      GtkIconTheme *icon_theme;
+
+      icon_theme = gtk_icon_theme_get_for_screen (gtk_widget_get_screen (GTK_WIDGET (window)));
+
+      g_signal_handlers_disconnect_by_func (icon_theme, update_themed_icon, window);
+    }
+    
   /* We don't clear the properties on the window, just figure the
    * window is going away.
    */
 
   info->realized = FALSE;
+
 }
 
 /**
@@ -2826,6 +2940,79 @@ gtk_window_set_icon (GtkWindow  *window,
   g_list_free (list);  
 }
 
+
+static void 
+update_themed_icon (GtkIconTheme *icon_theme,
+                   GtkWindow    *window)
+{
+  g_object_notify (G_OBJECT (window), "icon");
+  
+  gtk_window_unrealize_icon (window);
+  
+  if (GTK_WIDGET_REALIZED (window))
+    gtk_window_realize_icon (window);  
+}
+
+/**
+ * gtk_window_set_icon_name:
+ * @window: a #GtkWindow
+ * @name: the name of the themed icon
+ *
+ * Sets the icon for the window from a named themed icon. See
+ * the docs for #GtkIconTheme for more details. 
+ * 
+ * Note that this has nothing to do with the WM_ICON_NAME 
+ * property which is mentioned in the ICCCM.
+ *
+ * Since: 2.6
+ */
+void 
+gtk_window_set_icon_name (GtkWindow   *window,
+                         const gchar *name)
+{
+  GtkWindowIconInfo *info;
+  gchar *tmp;
+  
+  g_return_if_fail (GTK_IS_WINDOW (window));
+
+  info = ensure_icon_info (window);
+
+  tmp = info->icon_name;
+  info->icon_name = g_strdup (name);
+  g_free (tmp);
+
+  g_list_foreach (info->icon_list, (GFunc) g_object_unref, NULL);
+  g_list_free (info->icon_list);
+  
+  update_themed_icon (NULL, window);
+
+  g_object_notify (G_OBJECT (window), "icon_name");
+}
+
+/**
+ * gtk_window_get_icon_name:
+ * @window: a #GtkWindow
+ *
+ * Returns the name of the themed icon for the window,
+ * see gtk_window_set_icon_name().
+ *
+ * Returns: the icon name or %NULL if the window has 
+ * no themed icon
+ *
+ * Since: 2.6
+ */
+G_CONST_RETURN gchar *
+gtk_window_get_icon_name (GtkWindow *window)
+{
+  GtkWindowIconInfo *info;
+
+  g_return_val_if_fail (GTK_IS_WINDOW (window), NULL);
+
+  info = ensure_icon_info (window);
+
+  return info->icon_name;
+}
+
 /**
  * gtk_window_get_icon:
  * @window: a #GtkWindow
@@ -2985,6 +3172,56 @@ gtk_window_set_default_icon (GdkPixbuf *icon)
   g_list_free (list);
 }
 
+/**
+ * gtk_window_set_default_icon_name:
+ * @name: the name of the themed icon
+ * 
+ * Sets an icon to be used as fallback for windows that haven't
+ * had gtk_window_set_icon_list() called on them from a named
+ * themed icon, see gtk_window_set_icon_name().
+ *
+ * Since: 2.6
+ **/
+void
+gtk_window_set_default_icon_name (const gchar *name)
+{
+  GList *tmp_list;
+  GList *toplevels;
+
+  /* Update serial so we don't used cached pixmaps/masks
+   */
+  default_icon_serial++;
+
+  g_free (default_icon_name);
+  default_icon_name = g_strdup (name);
+
+  g_list_foreach (default_icon_list,
+                  (GFunc) g_object_unref, NULL);
+
+  g_list_free (default_icon_list);
+  default_icon_list = NULL;
+  
+  /* Update all toplevels */
+  toplevels = gtk_window_list_toplevels ();
+  tmp_list = toplevels;
+  while (tmp_list != NULL)
+    {
+      GtkWindowIconInfo *info;
+      GtkWindow *w = tmp_list->data;
+      
+      info = get_icon_info (w);
+      if (info && info->using_default_icon && info->using_themed_icon)
+        {
+          gtk_window_unrealize_icon (w);
+          if (GTK_WIDGET_REALIZED (w))
+            gtk_window_realize_icon (w);
+        }
+
+      tmp_list = tmp_list->next;
+    }
+  g_list_free (toplevels);
+}
+
 /**
  * gtk_window_set_default_icon_from_file:
  * @filename: location of icon file
index bcf6963e003b12d263a5920c4967cb3811ef7471..a52d675c0aa11039423e7a5b6e07fc87b0f4a082 100644 (file)
@@ -257,13 +257,18 @@ void       gtk_window_set_icon_list                (GtkWindow  *window,
 GList*     gtk_window_get_icon_list                (GtkWindow  *window);
 void       gtk_window_set_icon                     (GtkWindow  *window,
                                                     GdkPixbuf  *icon);
+void       gtk_window_set_icon_name                (GtkWindow   *window,
+                                                   const gchar *name);
 gboolean   gtk_window_set_icon_from_file           (GtkWindow   *window,
                                                    const gchar *filename,
                                                    GError     **err);
 GdkPixbuf* gtk_window_get_icon                     (GtkWindow  *window);
+G_CONST_RETURN 
+gchar     *gtk_window_get_icon_name                (GtkWindow  *window);
 void       gtk_window_set_default_icon_list        (GList      *list);
 GList*     gtk_window_get_default_icon_list        (void);
 void       gtk_window_set_default_icon             (GdkPixbuf  *icon);
+void       gtk_window_set_default_icon_name        (const gchar *name);
 gboolean   gtk_window_set_default_icon_from_file   (const gchar *filename,
                                                    GError     **err);